package com.relytosoft.mizar.media.analyze.services.service.structure.impl;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.relytosoft.dubhe.common.core.object.ResponseResult;
import com.relytosoft.dubhe.common.core.utils.BeanCopyUtils;
import com.relytosoft.dubhe.common.redis.utils.RedisUtil;
import com.relytosoft.mizar.media.analyze.services.service.control.ControlTypeService;
import com.relytosoft.mizar.media.analyze.services.service.control.ControlVerifyService;
import com.relytosoft.mizar.media.analyze.services.service.structure.AyStructureAlarmService;
import com.relytosoft.mizar.media.analyze.services.service.structure.AyStructureControlService;
import com.relytosoft.mizar.media.common.constant.SymbolConstants;
import com.relytosoft.mizar.media.common.entity.algo.*;
import com.relytosoft.mizar.media.common.entity.pojo.dto.AyDispositionPlanDto;
import com.relytosoft.mizar.media.common.entity.pojo.dto.controlCondition.TextNonVehicleConditionDto;
import com.relytosoft.mizar.media.common.entity.pojo.dto.controlCondition.TextPeopleConditionDto;
import com.relytosoft.mizar.media.common.entity.pojo.dto.controlCondition.TextVehicleConditionDto;
import com.relytosoft.mizar.media.common.entity.pojo.request.btdl.common.BtdlStructureControlReq;
import com.relytosoft.mizar.media.external.api.analyze.request.StruDataReqDto;
import com.relytosoft.mizar.media.external.api.analyze.service.StructureService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.ZoneId;
import java.util.*;

import static com.relytosoft.mizar.media.common.constant.AyCacheConstants.*;
import static com.relytosoft.mizar.media.common.constant.ControlConstants.*;

/**
 * @author wss
 * @version 1.0
 * @date 2022/5/23 17:08
 */
@Service
public class AyStructureControlServiceImpl implements AyStructureControlService {

    protected Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    ControlTypeService controlTypeService;
    @Autowired
    AyStructureAlarmService ayStructureAlarmService;
    @Resource
    StructureService structureService;
    @Autowired
    ControlVerifyService controlVerifyService;

    @Override
    public Boolean rawStructureVerify(AYVideoSlice ayVideoSlice, Map<String, String> bigPic) {

        List<AYVehicle> vehicleList = ayVideoSlice.getMotorVehicleList().getMotorVehicleObject();
        String deviceID = ayVideoSlice.getDeviceID();
        //遮挡车牌验证
        AYVehicle ayVehicle = new AYVehicle();
        if (coverVehicleVerify(vehicleList, ayVehicle)) {
            ayStructureAlarmService.structureCoverVehicleAlarm(ayVehicle, bigPic, deviceID);
            return true;
        }

        Object controlJson = RedisUtil.get(RAW_STRUCTURE_CONDITION + ayVideoSlice.getDeviceID());
        if (Objects.isNull(controlJson)) {
            return false;
        }
        List<AyDispositionPlanDto> ayDispositionPlanDtoS = JSON.parseArray(controlJson.toString(), AyDispositionPlanDto.class);
        Iterator<AyDispositionPlanDto> planDtoIterator = ayDispositionPlanDtoS.iterator();
        while (planDtoIterator.hasNext()) {
            AyDispositionPlanDto dispositionPlanDto = planDtoIterator.next();
            AYVideoSliceCommon ayVideoSliceCommon = new AYVideoSliceCommon();
            if (singleRawStructureVerify(dispositionPlanDto, ayVideoSlice, ayVideoSliceCommon)) {
                ayStructureAlarmService.structureAlarm(dispositionPlanDto, bigPic, ayVideoSliceCommon);
                return true;
            }
        }
        return false;
    }

    @Override
    public Boolean controlStructureVerify(BtdlStructureControlReq.Alarm alarm, String executeControlId) {
        if (Objects.isNull(alarm) || StrUtil.isBlank(executeControlId)) {
            return false;
        }
        Object controlDto = RedisUtil.get(CONTROL_STRUCTURE_CONDITION + executeControlId);
        //判定布控条件是否存在
        if (Objects.isNull(controlDto)) {
            return false;
        }
        AyDispositionPlanDto ayDispositionPlanDto = JSON.parseObject(controlDto.toString(), AyDispositionPlanDto.class);
        if (singleControlStructureVerify(ayDispositionPlanDto, alarm)) {
            ayStructureAlarmService.structureControlAlarm(ayDispositionPlanDto, alarm);
            return true;
        }
        return false;
    }

    /**
     * 单个原始结构化数据布控验证
     *
     * @param ayDispositionPlanDto 布控dto对象
     * @param ayVideoSlice         切片对象
     * @param ayVideoSliceCommon   报警明细对象
     * @return
     */
    public Boolean singleRawStructureVerify(AyDispositionPlanDto ayDispositionPlanDto, AYVideoSlice ayVideoSlice, AYVideoSliceCommon ayVideoSliceCommon) {
        //前置验证
        if (!controlVerifyService.controlFrontVerify(ayDispositionPlanDto, System.currentTimeMillis())) {
            return false;
        }
        //布控计划验证
        if (!controlVerifyService.controlTemplateVerify(ayDispositionPlanDto)) {
            return false;
        }
        //结构化条件验证
        return structureConditionVerify(ayVideoSlice, ayDispositionPlanDto, ayVideoSliceCommon);
    }

    /**
     * 单个布控结构化数据布控验证
     *
     * @param ayDispositionPlanDto
     * @param structureControlReqAlarm
     * @return
     */
    public Boolean singleControlStructureVerify(AyDispositionPlanDto ayDispositionPlanDto, BtdlStructureControlReq.Alarm structureControlReqAlarm) {
        Long markTime = structureControlReqAlarm.getAlarmData().getMarkTime();
        //前置验证
        if (!controlVerifyService.controlFrontVerify(ayDispositionPlanDto, markTime)) {
            return false;
        }
        //布控计划验证
        return controlVerifyService.controlTemplateVerify(ayDispositionPlanDto);
    }

    /**
     * 结构化布控条件验证
     *
     * @param ayDispositionPlanDto 布控dto对象
     * @param ayVideoSlice         切片对象
     * @param ayVideoSliceCommon   报警明细对象
     * @return
     */
    public Boolean structureConditionVerify(AYVideoSlice ayVideoSlice, AyDispositionPlanDto ayDispositionPlanDto, AYVideoSliceCommon ayVideoSliceCommon) {
        List<AYPerson> personList = ayVideoSlice.getPersonList().getPersonObject();
        List<AYVehicle> vehicleList = ayVideoSlice.getMotorVehicleList().getMotorVehicleObject();
        List<AYNonVehicle> nonVehicleList = ayVideoSlice.getNonMotorVehicleList().getNonMotorVehicleObject();
        //布控方式 人/机动车/非机动车
        int dispositionCategory = ayDispositionPlanDto.getDispositionCategory();
        switch (dispositionCategory) {
            case STRUCTURE_DISPOSITION_CATEGORY_PEOPLE:
                return controlPeopleVerify(personList, ayDispositionPlanDto, ayVideoSliceCommon);
            case STRUCTURE_DISPOSITION_CATEGORY_VEHICLE:
                return controlVehicleVerify(vehicleList, ayDispositionPlanDto, ayVideoSliceCommon);
            case STRUCTURE_DISPOSITION_CATEGORY_NON_VEHICLE:
                return controlNonVehicleVerify(nonVehicleList, ayDispositionPlanDto, ayVideoSliceCommon);
            default:
                return false;
        }
    }

    /**
     * 结构化布控行人验证
     *
     * @param ayDispositionPlanDto 布控dto对象
     * @param personList           行人集合对象
     * @param ayVideoSliceCommon   报警明细对象
     * @return
     */
    public Boolean controlPeopleVerify(List<AYPerson> personList, AyDispositionPlanDto ayDispositionPlanDto, AYVideoSliceCommon ayVideoSliceCommon) {
        if (personList.isEmpty()) {
            return false;
        }
        String dispositionText = ayDispositionPlanDto.getDispositionText();
        TextPeopleConditionDto textPeopleConditionDto = JSON.parseObject(dispositionText, TextPeopleConditionDto.class);
        //行人目前只支持文本条件布控
        if (Objects.equals(STRUCTURE_DISPOSITION_TYPE_TEST, ayDispositionPlanDto.getDispositionType())) {
            return controlTypeService.textPeopleVerify(personList, textPeopleConditionDto, ayVideoSliceCommon);
        }
        return false;
    }

    /**
     * 结构化布控车辆验证
     *
     * @param vehicleList
     * @return
     */
    public Boolean controlVehicleVerify(List<AYVehicle> vehicleList, AyDispositionPlanDto ayDispositionPlanDto, AYVideoSliceCommon ayVideoSliceCommon) {
        if (vehicleList.isEmpty()) {
            return false;
        }
        if (!controlVehicleFluentlyVerify(vehicleList, ayDispositionPlanDto)) {
            return false;
        }

        String dispositionText = ayDispositionPlanDto.getDispositionText();
        TextVehicleConditionDto textVehicleConditionDto = JSON.parseObject(dispositionText, TextVehicleConditionDto.class);
        Integer dispositionType = ayDispositionPlanDto.getDispositionType();
        switch (dispositionType) {
            case STRUCTURE_DISPOSITION_TYPE_TEST:
                return controlTypeService.textVehicleVerify(vehicleList, textVehicleConditionDto, ayVideoSliceCommon);
            case STRUCTURE_DISPOSITION_TYPE_IMAGE:
                return false;
            case STRUCTURE_DISPOSITION_VEHICLE_TYPE_GROUP:
                return vehicleGroupVerify(vehicleList, ayDispositionPlanDto, ayVideoSliceCommon);
            default:
                return false;
        }
    }

    /**
     * 验证车辆出现频率
     *
     * @param vehicleList
     * @param ayDispositionPlanDto
     * @return
     */
    public Boolean controlVehicleFluentlyVerify(List<AYVehicle> vehicleList, AyDispositionPlanDto ayDispositionPlanDto) {
        Object frequentlyObj = RedisUtil.get(AY_STRUCTURE_VEHICLE_FREQUENTLY);
        if (Objects.isNull(frequentlyObj)) {
            return true;
        }
        int intervalTime = Integer.parseInt(frequentlyObj.toString());
        StruDataReqDto struDataReqDto = new StruDataReqDto();
        struDataReqDto.setDeviceIds(Collections.singletonList(ayDispositionPlanDto.getDeviceId()));
        struDataReqDto.setDataType(2);
        struDataReqDto.setEndTime(cn.hutool.core.date.DateUtil.formatDateTime(new DateTime()));
        AYVehicle ayVehicle = new AYVehicle();
        struDataReqDto.setMotorVehicle(ayVehicle);

        Iterator<AYVehicle> iterator = vehicleList.iterator();
        while (iterator.hasNext()) {
            AYVehicle vehicle = iterator.next();
            String plateNo = vehicle.getPlateNo();
            ayVehicle.setPlateNo(plateNo);
            ResponseResult responseResult = structureService.searchStructureData(struDataReqDto);
            JSONObject jsonObject = JSON.parseObject(responseResult.toString());
            JSONObject result = jsonObject.getJSONObject("Result");
            Integer total = result.getInteger("total");
            if (total < intervalTime) {
                return false;
            }
        }
        return true;
    }

    /**
     * 结构化布控非机动车验证
     *
     * @param nonVehicleList
     * @return
     */
    public Boolean controlNonVehicleVerify(List<AYNonVehicle> nonVehicleList, AyDispositionPlanDto ayDispositionPlanDto, AYVideoSliceCommon ayVideoSliceCommon) {
        if (nonVehicleList.isEmpty()) {
            return false;
        }
        String dispositionText = ayDispositionPlanDto.getDispositionText();
        TextNonVehicleConditionDto textNonVehicleConditionDto = JSON.parseObject(dispositionText, TextNonVehicleConditionDto.class);
        //非机动车目前只支持文本条件布控
        if (Objects.equals(STRUCTURE_DISPOSITION_TYPE_TEST, ayDispositionPlanDto.getDispositionType())) {
            return controlTypeService.textNonVehicleVerify(nonVehicleList, textNonVehicleConditionDto, ayVideoSliceCommon);
        }
        return false;
    }

    /**
     * 结构化遮挡车牌验证
     *
     * @param vehicles
     */
    public Boolean coverVehicleVerify(List<AYVehicle> vehicles, AYVehicle ayVehicle) {
        if (vehicles.isEmpty()) {
            return false;
        }
        Iterator<AYVehicle> vehicleIterator = vehicles.iterator();
        while (vehicleIterator.hasNext()) {
            AYVehicle vehicle = vehicleIterator.next();
            String isCovered = vehicle.getIsCovered();
            String hasPlate = vehicle.getHasPlate();
            String trueStr = String.valueOf(BooleanUtil.toInt(true));
            if (!Objects.equals(trueStr, hasPlate) || Objects.equals(trueStr, isCovered)) {
                BeanCopyUtils.copy(vehicle, ayVehicle);
                return true;
            }
        }
        return false;
    }

    /**
     * 结构化车辆库验证
     *
     * @param vehicles
     */
    public Boolean  vehicleGroupVerify(List<AYVehicle> vehicles, AyDispositionPlanDto ayDispositionPlanDto, AYVideoSliceCommon ayVideoSliceCommon) {
        //识别车辆对象为空
        if (vehicles.isEmpty()) {
            return false;
        }
        String dtoVehicleGroupIds = ayDispositionPlanDto.getVehicleGroup();
        String dtoTempVehicleGroupIds = ayDispositionPlanDto.getTempVehicleGroup();
        List<String> vehicleGroupIds;

        //无正常车辆组集合id
        if (StrUtil.isNotBlank(dtoVehicleGroupIds) && !(vehicleGroupIds = StrUtil.split(dtoVehicleGroupIds, SymbolConstants.COMMA)).isEmpty()) {
            //正常车辆库验证
            if (vehicleContainVerify(vehicles, vehicleGroupIds, ayVideoSliceCommon)) {
                return true;
            }
        }

        List<String> tempVehicleGroupIds;
        //无临时车辆组集合id
        if (StrUtil.isBlank(dtoTempVehicleGroupIds) || (tempVehicleGroupIds = StrUtil.split(dtoTempVehicleGroupIds, SymbolConstants.COMMA)).isEmpty()) {
            return false;
        }
        //验证时间段
        long beginTime = ayDispositionPlanDto.getBeginTime().atZone(ZoneId.systemDefault()).toEpochSecond();
        long endTime = ayDispositionPlanDto.getEndTime().atZone(ZoneId.systemDefault()).toEpochSecond();
        long currentTime = System.currentTimeMillis();
        if (currentTime < beginTime || endTime > currentTime) {
            return false;
        }
        //临时车辆库集合验证
        return vehicleContainVerify(vehicles, tempVehicleGroupIds, ayVideoSliceCommon);
    }

    /**
     * 车辆是否在车辆库集合验证
     *
     * @param vehicles
     * @param vehicleGroupIds
     * @return
     */
    public Boolean vehicleContainVerify(List<AYVehicle> vehicles, List<String> vehicleGroupIds, AYVideoSliceCommon ayVideoSliceCommon) {
        Iterator<AYVehicle> vehicleIterator = vehicles.iterator();
        while (vehicleIterator.hasNext()) {
            AYVehicle ayVehicle = vehicleIterator.next();
            String plateNo = ayVehicle.getPlateNo();
            if (StrUtil.isBlank(plateNo)) {
                return false;
            }
            //验证车辆库set集合是否有布控车牌
            for (String vehicleGroupId : vehicleGroupIds) {
                if (RedisUtil.sHasKey(VEHICLE_GROUP + vehicleGroupId, plateNo)) {
                    BeanCopyUtils.copy(ayVehicle, ayVideoSliceCommon);
                    return true;
                }
            }
        }
        return false;
    }

}
